﻿// <copyright file="MainMenu.cs" company="ThorIndustry">Copyright (c) ThorIndustry. All rights reserved.</copyright>

#define TEST_no

using System.Collections.Generic;

public class WelcomeMenu: Menu
{
    public UnityEngine.GameObject SolutionShapePrefab;
    public UnityEngine.GameObject ShapePrefab;
    public UnityEngine.GameObject Quad;
    public UnityEngine.GameObject LogoFNSPrefab;
    public UnityEngine.GameObject moreInfoPrefab;

    public UnityEngine.GameObject LabelPrefab;
    public UnityEngine.GameObject FrisePrefab;

    private IViewService viewService;
    private ICameraService cameraService;

    private UnityEngine.GameObject frise;
    private UnityEngine.GUIText wallOfTextLabel;
    private UnityEngine.GUIText pleaseClickLabel;
    private UnityEngine.GUIText introLabel;
    private UnityEngine.GUIText titleLabel;
    private UnityEngine.GUIText copyrightLabel;
    private UnityEngine.GUITexture logoFNSImage;
    private Button moreInfoButton;

    private SolutionShape solutionShape;
    private Shape[] shapes;

    private int count = 0;
    private float timer = 0;
    private float maxTimer = 2;

    private static string wallOfText = "« C’est comme qui dirait le jeu que les Grecs ont appelé ostomachion. Ce sont des pièces en os, quatorze en tout, qui représentent des figures géométriques. Il y en a d’équilatérales, d’autres avec des côtés de longueur variée, ou encore symétriques, avec des angles droits ou obliques. On les appelle isocèles, isopleures, orthogones, scalènes. Grâce aux agencements divers de ces assemblages, on représente mille sortes de formes un éléphant monstrueux ou un sanglier brutal, une oie qui vole et un mirmillon sous les armes, un chasseur à l’affût et un chien qui aboie, et encore une tour, un canthare, une quantité innombrable de figures qui varient selon la plus ou moins grande habileté de chacun. Les compositions des gens adroits sont étonnantes, les assemblages des maladroits ridicules. »\nAusone (IVe s. apr. J.-C.), Lettre à Paul, 18 (trad. M. Lemoine, revue par V. Dasen)";
    private static string puzzleName = "Loculus_Square_Welcome";
    private static string labelText = "Toucher l'écran pour choisir une forme !";
    private static string introText = "Le mathématicien Archimède de Syracuse (IIIe s. av. J.-C.) aurait inventé ce jeu qui ressemble au Tangram chinois. Il se compose de 14 différentes formes géométriques. Ces pièces peuvent s'agencer de 536 façons différentes pour former un carré, mais permettent aussi de construire d'autres figures (éléphant, soldat, etc.). Le « puzzle » est connu sous différents noms : Stomachion, Ostomachion, Loculus ou « boîte » d’Archimède.";
    private static string titleText = "Loculus d'Archimède";
    private static string fnsText = "Réalisé par Florian Brulhart dans le cadre du projet FNS Angora <i>Veni, vidi, ludique</i>";
    private static string moreInfo = "En savoir plus...";
    private static string lessInfo = "Cacher le texte.";
            
    public override void Initialize(IGuiController guiController)
    {
        base.Initialize(guiController);

        this.viewService = Services.GetService<IViewService>();
        this.cameraService = Services.GetService<ICameraService>();

        this.InitializeMenu();
    }
    
    private void InitializeMenu()
    {
        float centerY = UnityEngine.Screen.height / 2;
        float x = 0.5f;

        // We have to create some "Frise" on the top.
        this.InitializeFrise();

        // We have to create some shape.
        this.GenerateShape();

        // Title.
        UnityEngine.GameObject titleGameObject = UnityEngine.GameObject.Instantiate(this.LabelPrefab) as UnityEngine.GameObject;
        this.titleLabel = titleGameObject.GetComponent<UnityEngine.GUIText>();
        UnityEngine.Transform labelTransform = titleGameObject.transform;
        labelTransform.parent = this.transform;
        this.titleLabel.text = WelcomeMenu.titleText;
        this.titleLabel.alignment = UnityEngine.TextAlignment.Left;
        this.titleLabel.anchor = UnityEngine.TextAnchor.LowerCenter;
        this.titleLabel.fontSize = UnityEngine.Mathf.RoundToInt(this.titleLabel.fontSize * GuiHelper.GetScreenSizeRatio());
        this.titleLabel.color = new UnityEngine.Color(241f / 255, 130f / 255, 77f / 255);

        UnityEngine.Rect rect = GuiHelper.FormatGuiTextArea(this.titleLabel, UnityEngine.Screen.width * 0.9f);
        labelTransform.localPosition = new UnityEngine.Vector3(0.5f, 0.8f, 0);
        this.titleLabel.pixelOffset = new UnityEngine.Vector2(0, 0);

        // Introduction.
        UnityEngine.GameObject introGameObject = UnityEngine.GameObject.Instantiate(this.LabelPrefab) as UnityEngine.GameObject;
        this.introLabel = introGameObject.GetComponent<UnityEngine.GUIText>();
        labelTransform = introGameObject.transform;
        labelTransform.parent = this.transform;
        this.introLabel.text = WelcomeMenu.introText;
        this.introLabel.alignment = UnityEngine.TextAlignment.Left;
        this.introLabel.anchor = UnityEngine.TextAnchor.UpperCenter;
        this.introLabel.fontSize = UnityEngine.Mathf.RoundToInt(this.introLabel.fontSize * GuiHelper.GetScreenSizeRatio() / 1.5f);
        this.introLabel.color = UnityEngine.Color.black;

        rect = GuiHelper.FormatGuiTextArea(this.introLabel, UnityEngine.Screen.width * 0.9f);
        labelTransform.localPosition = new UnityEngine.Vector3(0.5f, 0.8f, 0);
        this.introLabel.pixelOffset = new UnityEngine.Vector2(0, 0);

        float xMoreInfo = 0.5f + (rect.width / 2 / UnityEngine.Screen.width);
        float yMoreInfo = 0.8f - (rect.height / UnityEngine.Screen.height);

        // Add a button for displaying the wall of text.
        UnityEngine.GameObject moreInfoGameObject = UnityEngine.GameObject.Instantiate(this.moreInfoPrefab) as UnityEngine.GameObject;
        this.moreInfoButton = moreInfoGameObject.GetComponent<Button>();
        this.moreInfoButton.IsVisible = true;
        labelTransform = moreInfoGameObject.transform;
        labelTransform.parent = this.transform;
        this.moreInfoButton.GuiText.text = WelcomeMenu.moreInfo;
        this.moreInfoButton.GuiText.alignment = UnityEngine.TextAlignment.Left;
        this.moreInfoButton.GuiText.anchor = UnityEngine.TextAnchor.UpperRight;
        this.moreInfoButton.GuiText.fontSize = UnityEngine.Mathf.RoundToInt(this.introLabel.fontSize * 1.2f);
        this.moreInfoButton.GuiText.color = new UnityEngine.Color(241f / 255, 130f / 255, 77f / 255);

        rect = GuiHelper.FormatGuiTextArea(this.moreInfoButton.GuiText, UnityEngine.Screen.width);
        rect.width *= 1.1f;
        rect.height *= 1.1f;
        rect.x = -rect.width;
        rect.y = -rect.height;

        this.moreInfoButton.GuiTexture.pixelInset = rect;

        labelTransform.localPosition = new UnityEngine.Vector3(xMoreInfo, yMoreInfo, 0);
        this.moreInfoButton.GuiText.pixelOffset = new UnityEngine.Vector2(0, 0);
        this.moreInfoButton.Clicked += new System.EventHandler(MoreInfoButton_Clicked);

        // Add a label for starting the game.
        UnityEngine.GameObject pleaseClickGameObject = UnityEngine.GameObject.Instantiate(this.LabelPrefab) as UnityEngine.GameObject;
        this.pleaseClickLabel = pleaseClickGameObject.GetComponent<UnityEngine.GUIText>();
        labelTransform = pleaseClickGameObject.transform;
        labelTransform.parent = this.transform;
        this.pleaseClickLabel.text = WelcomeMenu.labelText;
        this.pleaseClickLabel.alignment = UnityEngine.TextAlignment.Center;
        this.pleaseClickLabel.anchor = UnityEngine.TextAnchor.UpperCenter;
        this.pleaseClickLabel.fontSize = UnityEngine.Mathf.RoundToInt(this.pleaseClickLabel.fontSize * GuiHelper.GetScreenSizeRatio());
        this.pleaseClickLabel.color = new UnityEngine.Color(241f / 255, 130f / 255, 77f / 255);

        rect = GuiHelper.FormatGuiTextArea(this.pleaseClickLabel, UnityEngine.Screen.width * 0.9f);
        labelTransform.localPosition = new UnityEngine.Vector3(0.5f, 0.1f, 0);

        this.pleaseClickLabel.pixelOffset = new UnityEngine.Vector2(0, 0);

        // Add the fns logo.
        UnityEngine.GameObject logoGameObject = UnityEngine.GameObject.Instantiate(this.LogoFNSPrefab) as UnityEngine.GameObject;
        this.logoFNSImage = logoGameObject.GetComponent<UnityEngine.GUITexture>();
        labelTransform = logoGameObject.transform;
        labelTransform.parent = this.transform;

        rect = new UnityEngine.Rect();
        rect.width = UnityEngine.Mathf.Min(300, 150 * GuiHelper.GetScreenSizeRatio());
        rect.height = rect.width / 3;
        rect.x = -rect.width;
        rect.y = rect.height * 0.1f;

        this.logoFNSImage.pixelInset = rect;

        labelTransform.localPosition = new UnityEngine.Vector3(0.95f, 0.05f, 0);
        
        // Add the copyright text.
        UnityEngine.GameObject copyrightGameObject = UnityEngine.GameObject.Instantiate(this.LabelPrefab) as UnityEngine.GameObject;
        this.copyrightLabel = copyrightGameObject.GetComponent<UnityEngine.GUIText>();
        labelTransform = copyrightGameObject.transform;
        labelTransform.parent = this.transform;
        this.copyrightLabel.text = WelcomeMenu.fnsText;
        this.copyrightLabel.alignment = UnityEngine.TextAlignment.Center;
        this.copyrightLabel.anchor = UnityEngine.TextAnchor.UpperRight;
        float fontFactor = UnityEngine.Mathf.Min(GuiHelper.GetScreenSizeRatio(), 2);
        this.copyrightLabel.fontSize = UnityEngine.Mathf.RoundToInt(this.copyrightLabel.fontSize * fontFactor / 3);
        this.copyrightLabel.color = UnityEngine.Color.black;
        this.copyrightLabel.richText = true;

        rect = GuiHelper.FormatGuiTextArea(this.copyrightLabel, rect.width);
        labelTransform.localPosition = new UnityEngine.Vector3(0.95f, 0.05f, 0);
        this.copyrightLabel.pixelOffset = new UnityEngine.Vector2(0, 0);

        // Add a wall of text.
        UnityEngine.GameObject wallOfTextGameObject = UnityEngine.GameObject.Instantiate(this.LabelPrefab) as UnityEngine.GameObject;
        this.wallOfTextLabel = wallOfTextGameObject.GetComponent<UnityEngine.GUIText>();
        labelTransform = wallOfTextGameObject.transform;
        labelTransform.parent = this.transform;
        this.wallOfTextLabel.text = WelcomeMenu.wallOfText;
        this.wallOfTextLabel.alignment = UnityEngine.TextAlignment.Left;
        this.wallOfTextLabel.anchor = UnityEngine.TextAnchor.UpperCenter;
        this.wallOfTextLabel.fontSize = UnityEngine.Mathf.RoundToInt(this.wallOfTextLabel.fontSize * GuiHelper.GetScreenSizeRatio() / 1.2f);
        this.wallOfTextLabel.color = UnityEngine.Color.black;

        rect = GuiHelper.FormatGuiTextArea(this.wallOfTextLabel, UnityEngine.Screen.width * 0.7f);
        labelTransform.localPosition = new UnityEngine.Vector3(0.5f, 0.65f, 0);
        this.wallOfTextLabel.pixelOffset = new UnityEngine.Vector2(0, 0);
        this.wallOfTextLabel.gameObject.SetActive(false);
    }

    private void MoreInfoButton_Clicked(object sender, System.EventArgs e)
    {
        bool moreInfo = !this.wallOfTextLabel.gameObject.activeSelf;

        // Show wall of text.
        this.wallOfTextLabel.gameObject.SetActive(moreInfo);

        // Hide introduction.
        // this.introLabel.gameObject.SetActive(false);

        // Hide shapes.
        this.solutionShape.gameObject.SetActive(!moreInfo);
        for (int index = 0; index < this.shapes.Length; ++index)
        {
            this.shapes[index].gameObject.SetActive(!moreInfo);
        }

        // Hide moreInfo.       
        if (moreInfo)
        {
            this.moreInfoButton.GuiText.text = WelcomeMenu.lessInfo;
        }
        else
        {
            this.moreInfoButton.GuiText.text = WelcomeMenu.moreInfo;
        }
    }

    public override void Show(params object[] parameters)
    {
        base.Show(parameters);

        this.ToggleShow(true);
    }

    public override void Hide()
    {
        base.Hide();

        this.ToggleShow(false);
    }

    protected virtual void OnMouseDown()
    {
        // Show puzzle menu.
        this.GuiController.ShowMenu(typeof(PuzzleChoiceMenu));
    }

    private void DetailButton_Click()
    {
        // Toggle label and shape visibility.
    }

    private void InitializeFrise()
    {
        this.frise = UnityEngine.GameObject.Instantiate(this.FrisePrefab) as UnityEngine.GameObject;
        this.UpdateFrise();
    }

    private void UpdateFrise()
    {
        // Texture size.
        float textureHeight = 104;
        float textureWidth = 227;

        // texture scale.
        float quadWidth = UnityEngine.Screen.width;
        float quadHeight = UnityEngine.Screen.height * 0.1f;

        float scale = quadWidth / (quadHeight / textureHeight * textureWidth);
        this.frise.renderer.material.mainTextureScale = new UnityEngine.Vector2(scale, 1);
        
        // Quad scale.
		UnityEngine.Vector3 worldQuadSize = new UnityEngine.Vector3(2 * this.cameraService.Camera.orthographicSize * this.cameraService.AspectRatio, 2 * this.cameraService.Camera.orthographicSize * 0.1f);
        this.frise.transform.localScale = new UnityEngine.Vector3(worldQuadSize.x, worldQuadSize.y);

        // Position.
        UnityEngine.Vector3 screenPosition = new UnityEngine.Vector3(quadWidth / 2, UnityEngine.Screen.height - (quadHeight / 2), 0);
        UnityEngine.Vector3 worldPosition = UnityEngine.Camera.main.ScreenToWorldPoint(screenPosition);
        worldPosition.z = 1;

        this.frise.transform.position = worldPosition;
    }

    private void GenerateShape()
    {
        IDatatableService datatableService = Services.GetService<IDatatableService>();

        IDatatable<PuzzleDefinition> puzzleDefinitionDatatable = datatableService.GetDatatable<PuzzleDefinition>();
        PuzzleDefinition puzzleDefinition = puzzleDefinitionDatatable.GetValue(WelcomeMenu.puzzleName);
        PuzzleSolutionShape shape = new PuzzleSolutionShape(puzzleDefinition.Solution);
        shape.Initialize();

        this.solutionShape = PuzzleView.GenerateSolutionShape(shape, this.viewService.CurrentPaletteDefinition.HintColor.Color, this.transform, this.SolutionShapePrefab);

        Puzzle puzzle = new Puzzle();
        puzzle.Initialize(puzzleDefinition);

        this.shapes = new Shape[puzzle.Shapes.Length];

        for (int index = 0; index < puzzle.Shapes.Length; ++index)
        {
            UnityEngine.Color color = UnityEngine.Color.black;
            color = this.viewService.CurrentPaletteDefinition.ShapeColors[index % this.viewService.CurrentPaletteDefinition.ShapeColors.Length].Color;

            this.shapes[index] = PuzzleView.GenerateShape(puzzle.Shapes[index], color, this.transform, this.ShapePrefab);
            this.shapes[index].SelectionIndex = index;

            this.shapes[index].Initialize();
            this.shapes[index].CanMove = false;
        }
    }

    private void Update()
    {
        if (this.solutionShape == null ||
            !this.IsVisible)
        {
#if TEST
            this.UpdateFrise();
#endif
            return;
        }

        if (this.solutionShape != null &&
            this.cameraService != null)
        {
            // We want to place the camera as the solution shape does not go out of the screen.
            float widthAtGround = this.solutionShape.ShapeWidth;
            widthAtGround = UnityEngine.Mathf.Max(widthAtGround, 20);

            // As I am in an ortographic camera, the orthographic width is computed with this formulas.
            // orthograhic width = UnityUnitWidth / screenWidth * screenHeight/2
            float orthographicSizeFromHorizontal = widthAtGround / UnityEngine.Screen.width * UnityEngine.Screen.height / 2;
            float orthographicSizeFromVertical = ((this.solutionShape.ShapeHeight * 2.0f) / 2) + 2;

            this.cameraService.SetOrthograhicSize(UnityEngine.Mathf.Max(orthographicSizeFromHorizontal, orthographicSizeFromVertical));

            this.UpdateFrise();
        }

        // Check for back.
        if (UnityEngine.Input.GetKeyUp(UnityEngine.KeyCode.Escape) &&
            UnityEngine.Input.touchCount == 3)
        {
            this.count++;

            if (this.count >= 10)
            {
                // this.puzzleView.ViewService.Activate(typeof(OutGameView));
                UnityEngine.Application.Quit();
                return;
            }
        }
        
        if (count > 0)
        {
            this.timer += UnityEngine.Time.deltaTime;

            if (this.timer >= this.maxTimer)
            {
                count = 0;
                this.timer = 0;
            }
        }
        else
        {
            this.timer = 0;
        }

        // Check if the mouse is over the overlay button...
        if (this.moreInfoButton.HitTest(UnityEngine.Input.mousePosition))
        {
            return;
        }

        if (this.IsButtonDown())
        {
            this.GuiController.ShowMenu(typeof(PuzzleChoiceMenu), "Loculus");
        }
    }

    private void ToggleShow(bool show)
    {
        this.solutionShape.gameObject.SetActive(show);
        for (int index = 0; index < this.shapes.Length; ++index)
        {
            this.shapes[index].gameObject.SetActive(show);
        }
        
#if !TEST
        this.frise.SetActive(show);
#endif
        this.pleaseClickLabel.gameObject.SetActive(show);
        this.introLabel.gameObject.SetActive(show);
        this.titleLabel.gameObject.SetActive(show);
        this.copyrightLabel.gameObject.SetActive(show);
        this.logoFNSImage.gameObject.SetActive(show);
        this.moreInfoButton.gameObject.SetActive(show);
        this.wallOfTextLabel.gameObject.SetActive(false);

        this.moreInfoButton.GuiText.text = WelcomeMenu.moreInfo;

        // Show the backgouround picture.
#if !TEST
        this.Quad.SetActive(!show);
#endif
    }

    private bool IsButtonDown()
    {
#if (UNITY_IPHONE || UNITY_ANDROID)
        return UnityEngine.Input.touchCount == 1 &&
               UnityEngine.Input.touches[0].phase == UnityEngine.TouchPhase.Began;
#else
        return UnityEngine.Input.GetMouseButtonDown(0);
#endif
    }

    private bool IsButtonUp()
    {
#if (UNITY_IPHONE || UNITY_ANDROID)
        return UnityEngine.Input.touchCount == 1 &&
               (UnityEngine.Input.touches[0].phase == UnityEngine.TouchPhase.Ended ||
                UnityEngine.Input.touches[0].phase == UnityEngine.TouchPhase.Canceled);
#else
        return UnityEngine.Input.GetMouseButtonUp(0);
#endif
    }
}
